#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.api import urlfetch
from xml.dom import minidom
import urllib
import sys
import re



###
#
# GetInput is the class to print the page to handle user input
#
###

class GetInput(webapp.RequestHandler):
    def get(self):
		self.response.headers['Content-Type'] = 'text/html'
		self.response.out.write("""
			<html>
				<head>
					<title>Pubmed2Wordle</title>
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-18540127-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
				
				</head>
				<body>
					<form action="/search" method="get">
						<input type="text" name="query" size=25 />
						<input type="submit" /><br />
						Data: 
						<INPUT TYPE=CHECKBOX NAME="title" checked />Title  
						<INPUT TYPE=CHECKBOX NAME="abstract" checked />Abstract
						<!-- <INPUT TYPE=CHECKBOX NAME="authors" />Authors -->
						<INPUT TYPE=CHECKBOX NAME="year" />Year<br />
					</form>
					Examples: <a href="/search?query=%22su+ai%22[au]">"su ai"[au]</a>, <a href="/search?query=%22neylon+c%22[au]">"neylon c"[au]</a>, <a href="/search?query=%22hogenesch+jb%22[au]">"hogenesch jb"[au]</a>, <a href="/search?query=%22jensen+lj%22[au]">"jensen lj"[au]</a><p />
					<hr />
					NOTE: Queries are capped at 500 results due to GAE limitations.  Feel free to <a href="http://code.google.com/p/pubmed2wordle/">download the code</a> to run it locally.  <p />
					NOTE 2: We also realize that this app is a bit buggy, with some queries failing for cryptic reasons.  If you find one, feel free to <a href="http://code.google.com/p/pubmed2wordle/issues/list">log the bug</a> in the issue tracker so we know about it.  <p />

				</body>
			</html>""")


###
#
# Search is the class to handle a real query
#
###

class Search(webapp.RequestHandler):

	### Initialize
	def __init__(self):
		self.rpcResults = []


	### MAIN 
	def get(self):
		self.parseParams()
		self.printHeader()
		pmidList = self.executeSearch()
		text = self.getArticleText(pmidList)
#		self.response.out.write( "\nTEXT: "+text )
		self.printWordleLink(text)
		self.printTagxedoLink()
		self.printPmidList(pmidList)
		self.printTextInfo(text)
		self.printFooter()


	### Parse the input parameters
	def parseParams(self):
		self.query=self.request.get('query')

		## parse the possible fields to retrieve
		self.fields = {}
		for field in ("title","abstract","year","authors"):
			if( self.request.get(field) != '' ):
				self.fields[field] = 1

		### set defaults
		if( len(self.fields) == 0 ):
			self.fields['title'] = 1
			self.fields['abstract'] = 1

		### check params
#		for key in self.fields:
#			self.response.out.write("F: "+key)

		
	### Print the HTML header
	def printHeader(self):
		self.response.headers['Content-Type'] = 'text/html'
		self.response.out.write("""
			<html>
				<head>
					<title>Pubmed2Wordle</title>
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-18540127-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
				
				</head>
				<body>
					Searching Pubmed for: """+self.query+"<br>")
	

	### Print the HTML Footer
	def printFooter(self):
		self.response.out.write("""
		        </body>
			</html>""");

	
	### Execute the PubMed search via eUtils, retrieve PMID list
	def executeSearch(self):
		eSearchURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi'
		urlParams = {
			'db': 'pubmed',
			'retmode': 'xml',
			'term': self.query,
			'email': 'asu@gnf.org',
			'retmax': '500'
            }
		try:
			f = urllib.urlopen( eSearchURL, urllib.urlencode(urlParams) )
			dom = minidom.parse(f)
		except:
			raise NameError("Error executing search.")
#			sys.exit(1)


		pubmedList = dom.getElementsByTagName('Id')
		pmidList = []
		for pubmedEntry in pubmedList:
#			self.response.out.write("A: " + pubmedEntry.firstChild.nodeValue + "<br>" )
			pmidList.append(pubmedEntry.firstChild.nodeValue)

#		self.response.out.write( ",".join(pmidList) )			
#		self.response.out.write(dom.toprettyxml())
		return( pmidList )


	### Print the list of PMIDs for the search
	def printPmidList(self, pmidList):
		self.response.out.write( '<hr /><a href="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&cmd=Search&term='+urllib.quote(self.query)+'">' )
		self.response.out.write( "Found "+str(len(pmidList))+" results</a>: " + ", ".join(pmidList)+"<br>\n" )

	
	### For each PMID, retrieve the requested fields
	def getArticleText(self, pmidList):
#		self.response.out.write( "Z ("+str(len(pmidList))+"): " + ",".join(pmidList) )

		def makeURLs(pmidList):
			eFetchURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi'
			chunkSize = 75
			startPos = range(0,len(pmidList),chunkSize)
			urls = []
			for s in startPos:
				ids = ",".join([str(x) for x in pmidList[s:s+chunkSize]])
				urlParams = {
					'db': 'pubmed',
					'retmode': 'xml',
					'email': 'asu@gnf.org',
					'id': ids
				}
				urls.append(eFetchURL+"?"+urllib.urlencode(urlParams))
			
			return( urls )

		def handle_result(rpc):
			result = rpc.get_result()
#			self.response.out.write("Got result\n"+result.content+"\n")
			self.rpcResults.append(result)

		# Use a helper function to define the scope of the callback.
		def create_callback(rpc):
			return lambda: handle_result(rpc)
	
		urls = makeURLs( pmidList )

#		self.response.out.write("Spawned "+str(len(urls))+" jobs<br>\n")

		rpcs = []
		for url in urls:
			self.response.out.write("URL: "+url+"<br>\n")
			rpc = urlfetch.create_rpc()
			rpc.callback = create_callback(rpc)
			urlfetch.make_fetch_call(rpc, url)
			rpcs.append(rpc)

		# Finish all RPCs, and let callbacks process the results.
		for rpc in rpcs:
			rpc.wait()

#		self.response.out.write("Found RPC: "+str(len(self.rpcResults))+"\n")
		articleList = []
		for result in self.rpcResults:
#			self.response.out.write("*******RESULT: "+str(result.status_code)+"\n"+result.content+"\n******\n")
			dom = minidom.parseString(result.content)
			articleList.extend(dom.getElementsByTagName('PubmedArticle'))

#		self.response.out.write("Found Articles: "+str(len(articleList))+"\n")

		outputText = ''

		for article in articleList:
			try:
				if( "title" in self.fields ):
					titleNode = article.getElementsByTagName('ArticleTitle')[0]
#					self.response.out.write( titleNode.firstChild.nodeValue+"<br>\n" )
					outputText = outputText + titleNode.firstChild.nodeValue+" "
	
				if( "abstract" in self.fields ):
					abstractNode = article.getElementsByTagName('AbstractText')[0]
#					self.response.out.write( abstractNode.firstChild.nodeValue+"<p>\n" )
					outputText = outputText + abstractNode.firstChild.nodeValue+" "

				if( "year" in self.fields ):
					yearNode = article.getElementsByTagName('PubDate')[0].getElementsByTagName('Year')[0]
#					self.response.out.write( "Y: "+yearNode.firstChild.nodeValue+"<p>\n" )
					outputText = outputText + "Y"+yearNode.firstChild.nodeValue+" "

### This section is not ready for prime time yet...
#				if( "authors" in self.fields ):
#					authorList = article.getElementsByTagName('AuthorList')[0]
#					authors = authorList.getElementsByTagName('Author')
#					self.response.out.write("L: "+authors.length)
#					for author in authors:
#						lastName = author.getElementsByTagName('LastName')[0].firstChild.nodeValue
#						initials = author.getElementsByTagName('Initials')[0].firstChild.nodeValue
#						self.response.out.write(lastName+" "+initals)
#						outputText = outputText + lastname+"~"+initals + " "

			except:
#				self.response.out.write("ERROR!")
				pass
			
			
		return outputText

		
	def printWordleLink(self,text):
		self.response.out.write('''<form action="http://www.wordle.net/advanced" method="POST">
    <textarea name="text" style="display:none">'''+text+'''
    </textarea>
    <input type="submit" value="Submit to Wordle!">
</form>''')

	def printTagxedoLink(self):
		if( re.search("localhost",self.request.url) ):
			outURL = "http://pubmed2wordle.appspot.com"+self.request.path+"?"+self.request.query_string
		else:
			outURL = self.request.url

		self.response.out.write('<a href="http://www.tagxedo.com/app.html?url='+urllib.quote(outURL)+'&font=Duality&theme=Leah%20Duncan&shape=classic&orientation=Horizontal" target="_blank">Send to Tagxedo</a><p>\n')

	def printTextInfo(self,text):
		self.response.out.write('''<hr />\n<font color="gray">'''+text+'''</font><hr />''')
		
		

def main():
    application = webapp.WSGIApplication(
										[('/', GetInput),
										 ('/search', Search)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
